package com.squapsource.project_euler;

import java.util.Arrays;

public class Problem28 {

	private static final int SPIRAL_SIZE = 1001;

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Problem28 p28 = new Problem28();
		p28.process();

	}

	private void process() {
		int[][] spiral = getSpiral();
		for (int i = 0; i < SPIRAL_SIZE; i++) {

			System.out.println(Arrays.toString(spiral[i]));
		}
		int sum = addDiagonals(spiral);
		System.out.println(sum);
	}

	private int addDiagonals(int[][] spiral) {
		int sum = 0;
		for (int i =0; i< SPIRAL_SIZE; i++)
		{
			sum += spiral[i][i];
			sum += spiral[i][SPIRAL_SIZE-1-i];
		}
		sum --;
		return sum;
	}

	private int[][] getSpiral() {
		int[][] spiral = new int[SPIRAL_SIZE][SPIRAL_SIZE];

		int maxNum = SPIRAL_SIZE * SPIRAL_SIZE;
		Direction dir = Direction.WEST;
		int x = SPIRAL_SIZE - 1;
		int y = 0;
		for (int i = maxNum; i >= 1; i--) {
			spiral[y][x] = i;
			State state = getNewDir(x, y, dir, spiral);
			dir = state.dir;
			x = state.x;
			y = state.y;
		}
		return spiral;
	}

	private State getNewDir(int x, int y, Direction dir, int[][] spiral) {
		switch (dir) {
		case WEST:
			if (x - 1 < 0 || spiral[y][x - 1] != 0)
				return new State(x, y + 1, Direction.SOUTH);
			return new State(x - 1, y, dir);
		case SOUTH:
			if (y + 1 > SPIRAL_SIZE - 1 || spiral[y + 1][x] != 0)
				return new State(x + 1, y, Direction.EAST);
			return new State(x, y + 1, dir);
		case EAST:
			if (x + 1 > SPIRAL_SIZE - 1 || spiral[y][x + 1] != 0)
				return new State(x, y - 1, Direction.NORTH);
			return new State(x + 1, y, dir);
		case NORTH:
			if (y - 1 < 0 || spiral[y - 1][x] != 0)
				return new State(x - 1, y, Direction.WEST);
			return new State(x, y - 1, dir);

		}

		return null;
	}

	private enum Direction {
		WEST, SOUTH, EAST, NORTH

	}

	private class State {
		int x;
		int y;
		Direction dir;

		State(int x, int y, Direction dir) {
			super();
			this.x = x;
			this.y = y;
			this.dir = dir;
		}

	}
}
